<?php

namespace App\Http\Services;

use App\Http\Repositories\Daos\Course\CourseDao;
use App\Http\Repositories\Daos\Order\CourseOrderDao;
use App\Http\Repositories\Redis\CacheDataRedis;
use App\Http\Requests\UserContext;
use App\Http\Traits\Errors;
use App\Http\Traits\GlobalConstant;
use App\Jobs\EnrollSuccess;
use App\Models\Absence;
use App\Models\Campus;
use App\Models\CourseDuty;
use App\Models\CourseDutyTeacher;
use App\Models\CourseSection;
use App\Models\Estimate;
use App\Models\Leave;
use App\Models\Users;
use App\Util\Helper;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class CourseOrderService extends BaseService
{
    use Errors;

    protected $courseOrderDao;
    protected $courseDao;

    public function __construct(CourseOrderDao $courseOrderDao, CourseDao $courseDao)
    {
        $this->courseOrderDao = $courseOrderDao;
        $this->courseDao      = $courseDao;
    }

    public function lists(UserContext $userContext)
    {
        $userId    = $userContext->getId();
        $state     = request('state') ?? 0;
        $lat       = request('lat') ?? 0;
        $lng       = request('lng') ?? 0;
        $condition = [
            'user_id' => $userId,
        ];
        $page      = request('page') ?? 1;
        $size      = request('size') ?? 10;
        $field     = ['*'];
        $offset    = ($page * $size) - $size;
        $query     = $this->courseOrderDao->getModel()->with(["courseInfo" => function ($query) {
            $query->select(['id', 'teacher_id', 'name', 'discover', 'start_time', 'score', 'price']);
        }])->where($condition);

        if (!empty($state)) {
            $query = $query->where('status', $state);
        }
        $list = $query->with(["campusInfo" => function ($q) use ($lat, $lng) {
            $q->select(DB::raw("id, name,contact,logo,longitude,latitude,address,(6371 * acos(cos(radians(latitude)) * cos(radians($lat)) * cos(radians(longitude) - radians($lng)) + sin(radians(latitude)) * sin(radians($lat))))*1000 AS distance"));
        }])->withCount("courseSectionInfo")->withCount("courseSectionCompleteInfo")->orderBy('id', 'desc')->limit($size)->offset($offset)->get($field);
        if (!empty($list)) {
            foreach ($list as &$item) {
                $item['distance']   = $item->campusInfo->distance >= 1000 ? round($item->campusInfo->distance / 1000, 1) . "km" : ceil($item->campusInfo->distance) . "m";
                $item['status_tip'] = self::showOrderStatusTip($item);
                $item['teacher']    = $item->courseInfo->teacherInfo[0];
            }
            unset($item);
        }
        return $list;
    }

    public function createOrder(UserContext $userContext)
    {
        $userId   = $userContext->getId();
        $courseId = request('course_id') ?? 0;
        $campusId = request('campus_id') ?? 0;
        $nickname = request('nickname') ?? '';
        $sex      = request('sex') ?? 0;
        $age      = request('age') ?? '';
        $contact  = request('contact') ?? '';
        $address  = request('address') ?? '';
        $remark   = request('remark') ?? '';
        if (empty($courseId)) $this->showError('请选择课程');
        if (empty($nickname)) $this->showError('请输入昵称');
        if (empty($sex)) $this->showError('请选择性别');
        if (empty($age)) $this->showError('请选择年龄');
        if (empty($contact)) $this->showError('请输入联系电话');
        if (empty($address)) $this->showError('请输入居住小区');
        $courseInfo = $this->courseDao->getOne(['id' => $courseId, 'valid' => 1]);
        if (!$courseInfo) $this->showError('课程不存在或已失效');
        $courseOrderInfo = $this->courseOrderDao->getModel()->where('user_id', $userId)->where('course_id', $courseId)
            ->whereRaw('(status=1 or status=2)')->first();
        if (!empty($courseOrderInfo)) $this->showError('您已经报名该课程或者排队中');
        $courseSection = $this->courseDao->getModel()->where('id', $courseId)->whereIn('id', function ($query) {
            $query->select('course_id')->groupBy('course_id')->havingRaw('MAX(end_time) < ?', [time()])->from('course_section');
        })->first();
        $section       = DB::table('course_section')->where('course_id', $courseId)->orderBy('begin_time', 'asc')->first();
        if (!empty($courseSection)) $this->showError('当前课程已结课不可报名');
//        $leftSecond = CacheDataRedis::getRedisInstance()->systemConfig('basic.left_second') ?? 0;
//        if (time() + $leftSecond > $section->begin_time) $this->showError('课程即将开始不能报名');
        if (time() - 600 > $section->begin_time) $this->showError('课程已开始不能报名');
        $orderSn   = Helper::sn(20);
        $orderData = [
            'order_sn'    => $orderSn,
            'user_id'     => $userId,
            'campus_id'   => $campusId,
            'course_id'   => $courseId,
            'price'       => is_numeric($courseInfo['price']) ? $courseInfo['price'] : 0,
            'price_real'  => is_numeric($courseInfo['price']) ? $courseInfo['price'] : 0,
            'total_num'   => 1,
            'price_total' => is_numeric($courseInfo['price']) ? $courseInfo['price'] : 0,
            'pay_total'   => is_numeric($courseInfo['price']) ? $courseInfo['price'] : 0,
            'nickname'    => $nickname,
            'sex'         => $sex,
            'age'         => $age,
            'contact'     => $contact,
            'address'     => $address,
            'remark'      => $remark,
            'goods_snap'  => ['title' => $courseInfo['name'], 'discover' => $courseInfo['discover'], 'score' => $courseInfo['score'], 'video_url' => $courseInfo['video_url']]
        ];
        DB::beginTransaction();
        try {
            $count  = $this->courseOrderDao->count(['course_id' => $courseId, 'status' => 2]);//查询当前课程报名成功的订单数
            $status = 1;
            if ($count < $courseInfo['total']) {
                $status = 2;
            }
            $orderData['status'] = $status;
            //创建订单
            $order         = $this->courseOrderDao->save($orderData);
            $userInfo      = Users::find($userId);
            $campusInfo    = Campus::where('id', $campusId)->first();
            $courseSection = CourseSection::where('course_id', $courseId)->orderBy('begin_time', 'asc')->first();
            EnrollSuccess::dispatch($userInfo, $courseInfo, $campusInfo, $courseSection);
            DB::commit();
        } catch (\Exception $exception) {
            DB::rollBack();
            Log::error('报名或排队失败:' . $exception->getMessage());
            $this->showError('报名或排队失败');
        }
        return [
            'order_sn' => $orderSn,
            'id'       => $order['id'],
            'status'   => $status
        ];
    }

    public function orderDetail(UserContext $userContext)
    {
        $userId  = $userContext->getId();
        $orderId = request('o_id') ?? '';
        $lat     = request('lat') ?? 0;
        $lng     = request('lng') ?? 0;
        $detail  = $this->courseOrderDao->getModel()->where('id', $orderId)->where('user_id', $userId)
            ->with(["campusInfo"   => function ($q) use ($lat, $lng) {
                $q->select(DB::raw("id, name,contact,logo,longitude,latitude,address,(6371 * acos(cos(radians(latitude)) * cos(radians($lat)) * cos(radians(longitude) - radians($lng)) + sin(radians(latitude)) * sin(radians($lat))))*1000 AS distance"));
            }, "courseInfo"        => function ($query) {
                $query->select(['id', 'name', 'discover', 'class_room', 'start_time', 'score', 'price']);
            }, "courseSectionInfo" => function ($query) {
                $query->select(['id', 'course_id', 'name', 'serial_number', 'class_time', 'begin_time', 'end_time'])->orderBy('begin_time', 'asc');
            }])->withCount("courseSectionInfo")->withCount("courseSectionCompleteInfo")->withCount("courseSectionBegin")->first();
        if ($detail) {
            $detail->distance   = $detail->campusInfo->distance >= 1000 ? round($detail->campusInfo->distance / 1000, 1) . "km" : ceil($detail->campusInfo->distance) . "m";
            $detail->status_tip = self::showOrderStatusTip($detail);
            if ($detail->courseSectionInfo) {
                $flag       = true;
                $leftSecond = CacheDataRedis::getRedisInstance()->systemConfig('basic.left_second') ?? 0;
                $arr        = [];
                foreach ($detail->courseSectionInfo as $key => $item) {
                    if ($key == 0) {//第一章节
                        $detail->can_cancel = 0;
                        if (GlobalConstant::formatAllTimeOrHour(strtotime($item->class_time), $item->begin_time) - time() > $leftSecond) {
                            $detail->can_cancel = 1;
                        }
                    }
                    $sectionBeginTime      = GlobalConstant::formatAllTimeOrHour(strtotime($item->class_time), $item->begin_time);
                    $item->show_hui        = time() > $sectionBeginTime ? 1 : 0;
                    $item->show_yuan_index = 2000;
                    if ($flag && time() < $sectionBeginTime) {
                        $item->show_yuan_index = $key;
                        $detail->sksj          = $item->sk_time . ' ' . $item->begin_time . '-' . $item->end_time;
                        $flag                  = false;
                    }
                    //标签显示和可请假章节
//                    $sectionEndTime = GlobalConstant::formatAllTimeOrHour(strtotime($item->class_time), $item->end_time);
                    $leaveInfo   = Leave::where('user_id', $userId)->where('course_id', $detail['course_id'])->where('course_section_id', $item['id'])->first();
                    $dutyInfo    = CourseDuty::where('user_id', $userId)->where('course_id', $detail['course_id'])->where('course_section_id', $item['id'])->first();
                    $absenceInfo = Absence::where('user_id', $userId)->where('course_id', $detail['course_id'])->where('course_section_id', $item['id'])->first();
                    if (!empty($leaveInfo)) {
                        $item->tag_show  = '请假';
                        $item->tag_color = '#ACACAC';
                    } elseif (!empty($dutyInfo)) {
                        $item->tag_show  = '出勤';
                        $item->tag_color = '#96C0DF';
                    } elseif (!empty($absenceInfo)) {
                        $item->tag_show  = '缺勤';
                        $item->tag_color = '#E8A5A5';
                    } else {
                        $item->tag_show  = '';
                        $item->tag_color = '';
                        if (strtotime("-1 day", $sectionBeginTime) > time()) {
                            $arr[] = $item;
                        }
                    }

                }
                $detail->can_leave_section_list = $arr;
            }
        }
        return $detail;
    }

    public function firstOrder(UserContext $userContext)
    {
        $userId = $userContext->getId();
        $info   = $this->courseOrderDao->getOne(['user_id' => $userId], ['id' => 'desc'], ['nickname', 'age', 'sex', 'contact', 'address', 'remark']);
        if (!$info) {
            $info = new \stdClass();
        }
        return $info;
    }

    public function todayCourse(UserContext $userContext)
    {
        $userId    = $userContext->getId();
        $teacherId = $userContext->getTeacherId();
        $role      = request('role') ?? 0;
        $beginTime = strtotime(date('Y-m-d') . ' 00:00:00');
        $endTime   = strtotime(date('Y-m-d') . ' 23:59:59');
        if ($role == 2 || $role == 3) {
            $list = CourseSection::whereExists(function ($query) use ($userId, $beginTime, $endTime) {
                $query->where('user_id', $userId)->where('begin_time', '>=', $beginTime)->where('end_time', '<=', $endTime)->whereRaw('course_section.course_id = course_order.course_id')->select('course_section.course_id')->from('course_order');
            })->where('status', 1)->with(["courseInfo" => function ($query) {
                $query->select(['id', 'name', 'start_time', 'campus_id']);
            }])->whereIn('course_id', function ($query) {
                $query->where('is_cancel', 0)->select(['id'])->from('course');
            })->orderBy('begin_time', 'asc')->get(['id', 'name', 'serial_number', 'course_id', 'begin_time', 'end_time', 'class_time']);
        } else {
            $list = CourseSection::whereExists(function ($query) use ($teacherId, $beginTime, $endTime) {
                $query->where('teacher_id', $teacherId)->where('begin_time', '>=', $beginTime)->where('end_time', '<=', $endTime)->whereRaw('course_section.course_id = course.id')->select('course_section.course_id')->from('course');
            })->where('status', 1)->with(["courseInfo" => function ($query) {
                $query->select(['id', 'name', 'start_time', 'campus_id'])->where('is_cancel', 0);
            }])->whereIn('course_id', function ($query) {
                $query->where('is_cancel', 0)->select(['id'])->from('course');
            })->orderBy('begin_time', 'asc')->get(['id', 'name', 'serial_number', 'course_id', 'begin_time', 'end_time', 'class_time']);
        }

        $arr = [];
        if (!empty($list)) {
            foreach ($list as $item) {
                $data['section_id'] = $item['id'];
                $data['text']       = $item['courseInfo']['name'] . '(第' . $item['serial_number'] . '节)';
//                $data['value']       = $item['courseInfo']['id'];
                $data['course_id']   = $item['courseInfo']['id'];
                $data['value']       = $item['id'];
                $data['begin']       = GlobalConstant::formatAllTimeOrHour(strtotime($item['class_time']), $item['begin_time']);
                $data['end']         = GlobalConstant::formatAllTimeOrHour(strtotime($item['class_time']), $item['end_time']);
                $data['begin_time']  = $item['begin_time'];
                $data['end_time']    = $item['end_time'];
                $data['campus_info'] = Campus::where('id', $item['courseInfo']['campus_id'])->first(['id', 'name', 'latitude', 'longitude', 'address', 'pouch_distance']);
                if ($role == 1) {
                    $dutyList = CourseDutyTeacher::where('teacher_id', $teacherId)->where('course_id', $item['course_id'])->where('course_section_id', $item['id'])->get()->toArray();
                } else {
                    $dutyList = CourseDuty::where('user_id', $userId)->where('course_id', $item['course_id'])->where('course_section_id', $item['id'])->get()->toArray();
                }
//                Log::info('aaa'.$item['courseInfo']['id'].'=='.$item['id']);
                $leaveInfo = Leave::where('user_id', $userId)->where('course_id', $item['courseInfo']['id'])->where('course_section_id', $item['id'])->first();
                list($data['can_sign1'], $data['sign_str1']) = self::formatSign($dutyList, $leaveInfo);
                $data['second_day'] = strtotime(date('Y-m-d', strtotime($item['class_time'])) . ' 23:59:59');
                $arr[]              = $data;
            }
        }
//        $left_begin_second = CacheDataRedis::getRedisInstance()->systemConfig('basic.left_begin_second') ?? 0;
        return compact("arr");
    }

    protected static function formatSign($dutyList, $leaveInfo)
    {
        if (empty($dutyList) && empty($leaveInfo)) {
            return [true, '未签到'];
        }
        if (!empty($leaveInfo)) {
            return [false, '已请假'];
        }
        $can_sign1 = true;
        $sign_str1 = '未签到';
        foreach ($dutyList as $item) {
            if ($item['sign_type'] == 1) {
                $can_sign1 = false;
                $sign_str1 = '已签到 ' . GlobalConstant::formatAllTimeOrHour($item['sign_time']);
            }
        }
        return [$can_sign1, $sign_str1];
    }

    public static function showOrderStatusTip($order)
    {
        //    1排队中 	名额已满但又想报名时
//
//    2待上课		1报名成功且课程还未到课程course表的开课日期，2此课程所有章节未完成（不针对单个用户，指的是课程所有章节）
//
//    3已结课 	课程所有章节已完成
//
//    -1已取消		1报名成功主动取消2排队中主动取消
//
//    4报名失败    排队中一直到课程已经开始上课了都没报名成功
        if ($order['status'] == 1) {
            return '排队中';
        } elseif ($order['status'] == 2) {
            return '待上课';
        } elseif ($order['status'] == 3) {
            return '已结课';
        } elseif ($order['status'] == -1) {
            return '已取消';
        } else {
            return '报名失败';
        }
    }

    public function statics(UserContext $userContext)
    {
        $userId = $userContext->getId();
        return $this->courseOrderDao->getModel()->where('user_id', $userId)->whereIn('status', [1, 2])->groupBy('status')->select(DB::raw("status,count(*) as total"))->get();
    }

    public function orderCancel(UserContext $userContext)
    {
        $userId  = $userContext->getId();
        $orderId = request('o_id') ?? 0;
        if (empty($orderId)) $this->showError('取消报名异常');
        $order = $this->courseOrderDao->getOne(['id' => $orderId]);
        if (empty($order)) $this->showError('报名不存在');
        $firstSection = CourseSection::where('course_id', $order['course_id'])->orderBy('begin_time', 'asc')->first();
        $leftSecond   = CacheDataRedis::getRedisInstance()->systemConfig('basic.left_second') ?? 0;
        if (strtotime($firstSection['begin_time']) - time() < $leftSecond) $this->showError('临近开课不能取消');
        return $this->courseOrderDao->getModel()->where('user_id', $userId)->where('id', $orderId)->update(['status' => -1, 'cancel_reason' => '用户主动取消']);
    }

    public function checkApply(UserContext $userContext)
    {
        $userId   = $userContext->getId();
        $courseId = request('c_id') ?? 0;
        if (empty($courseId)) $this->showError('请传入课程');
        $info = $this->courseOrderDao->getOne(['user_id' => $userId, 'course_id' => $courseId], ['id' => 'desc']);//加排序，防止查询订单时之前取消过此课程的订单
        if (!$info) {
            return new \stdClass();
        }
        return $info;
    }

    public function staticsCount()
    {
        $status   = request('status') ?? 0;
        $courseId = request('course_id') ?? 0;
        $total    = $this->courseOrderDao->count(['status' => $status, 'course_id' => $courseId]);
        return compact("total");
    }

    public function createCheck(UserContext $userContext)
    {
        $userId   = $userContext->getId();
        $courseId = request('course_id') ?? 0;
        if (empty($courseId)) $this->showError('请选择课程');
        $courseInfo = $this->courseDao->getOne(['id' => $courseId, 'valid' => 1]);
        if (!$courseInfo) $this->showError('课程不存在或已失效');
        $courseOrderInfo = $this->courseOrderDao->getModel()->where('user_id', $userId)->where('course_id', $courseId)
            ->whereRaw('(status=1 or status=2)')->first();
        if (!empty($courseOrderInfo)) $this->showError('您已经报名该课程或者排队中');
        $courseSection = $this->courseDao->getModel()->where('id', $courseId)->whereIn('id', function ($query) {
            $query->select('course_id')->groupBy('course_id')->havingRaw('MAX(end_time) < ?', [time()])->from('course_section');
        })->first();
        if (!empty($courseSection)) $this->showError('当前课程已结课不可报名');
        $firstSection = DB::table('course_section')->where('course_id', $courseId)->orderBy('begin_time', 'asc')->first();
        if (empty($firstSection)) $this->showError('当前课程没有章节');
//        $leftSecond = CacheDataRedis::getRedisInstance()->systemConfig('basic.left_second') ?? 0;
//        if (time() + $leftSecond > $firstSection->begin_time) $this->showError('课程即将开始不能报名');
        if (time() -600 > $firstSection->begin_time) $this->showError('课程已开始不能报名');
        return true;
    }

    public function addLeave(UserContext $userContext)
    {
        $userId    = $userContext->getId();
        $orderId   = request('o_id') ?? 0;
        $sectionId = request('s_id') ?? 0;
        if (empty($sectionId)) $this->showError('请选择请假的章节');
        $info = $this->courseOrderDao->getOne(['id' => $orderId, 'user_id' => $userId]);
        if (!$info) $this->showError('当前报名不存在');
        $leaveInfo = Leave::where('user_id', $userId)->where('course_order_id', $orderId)->where('course_id', $info['course_id'])->where('course_section_id', $sectionId)->first();
        if ($leaveInfo) $this->showError('该章节已请过假');
        $courseSectionCount = CourseSection::where('course_id', $info['course_id'])->where('status', 1)->count();
        $half               = intval(ceil($courseSectionCount / 2));
        if ($info['leave'] >= $half) $this->showError('请假课节已超一半，已禁止请假！');

        $nextSection = CourseSection::where('course_id', $info['course_id'])->where('begin_time', '>', time())->orderBy('begin_time', 'asc')->first();
        if (!$nextSection) $this->showError('课程章节已完,无需请假');
        if (strtotime("-1 day", GlobalConstant::formatAllTimeOrHour(strtotime($nextSection['class_time']), $nextSection['begin_time'])) < time()) $this->showError('请至少下一节课开始前1天请假');
        DB::beginTransaction();
        try {
            $this->courseOrderDao->getModel()->where('id', $orderId)->where('user_id', $userId)->increment('leave', 1);
            Leave::create(['user_id' => $userId, 'course_order_id' => $orderId, 'course_id' => $info['course_id'], 'course_section_id' => $sectionId]);
            DB::commit();
            return true;
        } catch (\Exception $exception) {
            DB::rollBack();
            $this->showError($exception->getMessage());
        }

    }

    public function submitEstimate(UserContext $userContext)
    {
        $userId       = $userContext->getId();
        $orderId      = request('o_id') ?? 0;
        $teacherScore = request('teacher_score') ?? 0;
        $courseScore  = request('course_score') ?? 0;
        if (empty($orderId)) $this->showError('请选择评价的课程');
        if (empty($teacherScore)) $this->showError('请对教师评分');
        if (empty($courseScore)) $this->showError('请对课程评分');
        $order = $this->courseOrderDao->getOne(['id' => $orderId]);
        if (empty($order)) $this->showError('报名不存在');
        $course = $this->courseDao->getOne(['id' => $order['course_id']]);
        if (empty($course)) $this->showError('课程不存在');
        $detail = Estimate::where('order_id', $orderId)->where('user_id', $userId)->first();
        if (!empty($detail)) $this->showError('该课程和教师已评价过');
        try {
            DB::beginTransaction();

            $order->estimate_at   = time();
            $order->teacher_score = $teacherScore;
            $order->course_score  = $courseScore;
            $order->save();
            Estimate::create(['order_id' => $orderId, 'user_id' => $userId, 'course_id' => $order['course_id'], 'teacher_id' => $course['teacher_id'], 'teacher_score' => $teacherScore, 'course_score' => $courseScore]);
            DB::commit();
            return time();
        } catch (\Exception $exception) {
            DB::rollBack();
            $this->showError('评价失败');
        }
    }
}
